#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <linux/of_irq.h> 
#include <linux/irq.h>
#include <linux/platform_device.h> 
#include <linux/input.h>
#include <media/rc-core.h>

#define   IR1838_NAME	"ir1838" 
#define   IR1838_NUM	1

static struct rc_map_table ir1838_carmp3[] = {
	{ 0xA2, KEY_ESC },  			{ 0x62, KEY_MODE },       { 0xE2, KEY_DELETE },
	{ 0x22, KEY_ENTER },      		{ 0x02, KEY_LEFT },       { 0xC2, KEY_RIGHT },
	{ 0xE0, KEY_TAB },    			{ 0xA8, KEY_DOWN },   	  { 0x90, KEY_UP },
	{ 0x68, KEY_0 },            	{ 0x98, KEY_REFRESH },    { 0xb0, KEY_SPACE },
	{ 0x30, KEY_1 },             	{ 0x18, KEY_2 },          { 0x7A, KEY_3 },	
	{ 0x10, KEY_4 },             	{ 0x38, KEY_5 },          { 0x5A, KEY_6 },
	{ 0x42, KEY_7 },             	{ 0x4A, KEY_8 },          { 0x52, KEY_9 },
};

struct ir1838_st
{
	int gpio;
	int irqnum;
	unsigned char code;
	struct device_node *node;
	struct input_dev *inputdev;
};
static struct ir1838_st ir1838;

static int irRecvData[66]={0};

static irqreturn_t ir1838_handler(int irqnum, void *dev)
{
	static u64 last_get_time = 0;
	static int i=0;
	u64 temp =0,realTime=0;
	u8 data =0,data1=0;

	temp = ktime_get_boot_ns();
	realTime = temp-last_get_time;
	if(realTime>20000000)
	{
		i=0;
	}
	else
	{
		irRecvData[i++] = temp-last_get_time;
		if(i>=66)
		{	
			for(i=34;i<50;i+=2)
			{
				if((irRecvData[i]<800000) && (irRecvData[i+1]<1800000 && irRecvData[i+1]>1300000))
				{
					data |= 1<<(7-(i-34)/2);
				}
				else if((irRecvData[i]<800000) && (irRecvData[i+1]<800000))
				{
					data &= ~(1<<(7-(i-34)/2));
				}
			}

			for(i=50;i<65;i+=2)
			{
				if((irRecvData[i]<800000) && (irRecvData[i+1]<1800000 && irRecvData[i+1]>1300000))
				{
					data1 |= 1<<(7-(i-50)/2);
				}
				else if((irRecvData[i]<800000) && (irRecvData[i+1]<800000))
				{
					data1 &= ~(1<<(7-(i-50)/2));
				}
			}
			if((data|data1) == 0xff)
			{
				for(i=0;i<21;i++)
				{
					if(ir1838_carmp3[i].scancode == data)
					{
						input_report_key(ir1838.inputdev, ir1838_carmp3[i].keycode, 1);
						input_sync(ir1838.inputdev);
						input_report_key(ir1838.inputdev, ir1838_carmp3[i].keycode, 0);
						input_sync(ir1838.inputdev);
						break;
					}	
				}
			}
			
			i=0;
		}
	}
	last_get_time = temp;

	return IRQ_RETVAL(IRQ_HANDLED);
}

static int ir1838_probe(struct platform_device *dev)
{
	int ret =0;
	int i=0;
	
	//获取node节点
	ir1838.node = dev->dev.of_node;

	//获取IO口
	ir1838.gpio = of_get_named_gpio(ir1838.node, "gpios", 0);
	if(ir1838.gpio <0)
	{
		printk("of_get_named_gpio error\r\n");
		goto gpio_err;
	}

	ret = gpio_request(ir1838.gpio, IR1838_NAME);
	if(ret <0)
	{
		printk("gpio_request error\r\n");
		goto gpio_err;
	}

	ret = gpio_direction_input(ir1838.gpio);
	if(ret <0)
	{
		printk("gpio_direction_input error\r\n");
		goto direction_err;
	}

	//获取中断
	ir1838.irqnum = irq_of_parse_and_map(ir1838.node, 0);
	if(ir1838.irqnum <0)
	{
		printk("irq_of_parse_and_map error\r\n");
		goto direction_err;
	}

	ret = request_irq(ir1838.irqnum, ir1838_handler, IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, IR1838_NAME, NULL);
	if(ret <0)
	{
		printk("gpio_direction_input error\r\n");
		goto direction_err;
	}

	//创建输入设备
	ir1838.inputdev = input_allocate_device();
	if(IS_ERR(ir1838.inputdev))
	{
		printk("input_allocate_device error\r\n");
		goto input_err;
	}

	//设置input上报事件
	ir1838.inputdev->name = IR1838_NAME;
	__set_bit(EV_KEY, ir1838.inputdev->evbit);
	for(i=0;i<21;i++)
	{
		__set_bit(ir1838_carmp3[i].keycode, ir1838.inputdev->keybit);
	}

	//注册输入设备
	ret = input_register_device(ir1838.inputdev);
	if(ret <0)
	{
		printk("input_register_device error\r\n");
		goto input_register_err;
	}

	printk("ir1838_probe sucess\r\n");
	return 0;

input_register_err:
	input_free_device(ir1838.inputdev);
input_err:
	free_irq(ir1838.irqnum, NULL);
direction_err:
	gpio_free(ir1838.gpio);
gpio_err:
	return -EINVAL;
}

static int ir1838_remove(struct platform_device *dev)
{
	//释放GIOP、中断
	free_irq(ir1838.irqnum, NULL);
	gpio_free(ir1838.gpio);

	//注销输入设备
	input_unregister_device(ir1838.inputdev);
	input_free_device(ir1838.inputdev);

	printk("ir1838_remove sucess\r\n");
	return 0;
}

static const struct platform_device_id ir1838_idTable[]=
{
	{"ir1838",0},
	{}
};

static const struct of_device_id ir1838_of_match[]=
{
	{.compatible="ir1838"},
	{}
};

static struct platform_driver ir1838_dev = 
{
	.probe 	= ir1838_probe,
	.remove = ir1838_remove,
	.driver = {
		.owner 			= THIS_MODULE,
		.name 			= "ir1838",
		.of_match_table = ir1838_of_match,
	},
	.id_table = ir1838_idTable,
};

static int __init ir1838_init(void)
{
	return platform_driver_register(&ir1838_dev);
}

static void __exit ir1838_exit(void)
{
	platform_driver_unregister(&ir1838_dev);
}

module_init(ir1838_init);
module_exit(ir1838_exit);
MODULE_AUTHOR("jtb");
MODULE_LICENSE("GPL");

